const RBAC = require('./rbac-a');
const Provider = RBAC.providers.JsonProvider;
// 缓存的KEY
const RBAC_CACHE_KEY = 'auth_rule';

// https://github.com/yanickrochon/rbac-a

module.exports = {
  rbac: null,

  getRules: async function() { // 加载访问规则数据
    // https://www.npmjs.com/package/rbac-a
    const roles = await think.model('role').select();
    const users = await think.model('user').field('id,username').setRelation(false).select();
    const rules = {roles: {}, users: {}};
    if (roles) {
      for (const role of roles) {
        let permissions = await think.model('role_auth').where({role_id: role.id}).setRelation(false).getField('id');
        // permissions=permissions.join(',').split(',');
        if (permissions.length > 0) {
          permissions = permissions.join(',').split(',');
        } else {
          permissions = [];
        }
        rules.roles[role.name] = {
          'inherited': role.parent ? [role.parent.name] : [],
          'permissions': permissions || [],
          'attributes': []
        };
      }
    }
    if (users) {
      for (const user of users) {
        let roles1 = await think.model('role').alias('r').join({
          table: 'user_role',
          join: 'left',
          as: 'ur',
          on: ['r.id', 'ur.role_id']
          // field:'uid'
        }).where({'ur.uid': user.id}).setRelation(false).getField('name');

        roles1 = roles1.join(',').split(',');
        rules.users[user.username] = roles1 || [];
      }
    }
    think.logger.debug('加载访问规则');
    return rules;
  },

  /**
   * 更新访问规则
   * @returns {Promise<void>}
   */
  updateAuthRules: async function() {
    // 如果缓存存在，直接读取缓存
    await think.cache(RBAC_CACHE_KEY, async() => {
      think.logger.debug('重新从数据库加载规则文件');
      const rules = await this.getRules();
      this.rbac = new RBAC({
        provider: new Provider(rules) // 需要动态获取规则，后台修改授权必须重启服务才能使规则生效
      });
      return rules;
    }, {
      // timeout: 60 * 1000, //1分钟
    });
  },

  // 检测用户是都有权限访问指定的路由相应的方法
  checkRouterPath: async function(user, path, method = 'get') {
    // 找出所有能够访问该路径的角色列表
    const map = {};
    map[`ra.${method}`] = 1;
    map['r.path'] = path;

    const entity = await think.model('role_auth').alias('ra').join({
      table: 'resource',
      join: 'left',
      as: 'r',
      on: ['r.id', 'ra.resource_id']
    }).where(map).getField('ra.id');

    if (!think.isEmpty(entity)) {
      // think.logger.debug(entity);
      // entity='8f221801-08b8-11e9-acd4-00ff5adc8e6e';

      try {
        return await this.rbac.check(user, entity);
      } catch (e) {
        return false;
      }

      // const allowed = await this.check(user, entity).then(function (allowed) {
      //	if(allowed) {
      //		think.logger.debug('通过授权检测');
      //		return true;
      //	} else {
      //		// think.logger.error('没通过授权检测');
      //		return false;
      //	}
      //	// return allowed;
      // }).catch(function (err) {
      //	think.logger.error(err && err.stack || err || 'ERROR');
      //	return false;
      // });

      // return allowed;
    }
    return false;
  }

};
